package br.ufpe.cin.imlm2.util.options;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * Every option field must be INITIALIZED.<br>
 * Every option field must start with the prefix '__' , e.g. __myOptionField <br>
 * 
 * 
 * @author Irineu
 * 
 */
public abstract class Options implements IOptions {

	private static final String LIST_SEPARATOR = ";";
	protected List<Option> options;

	protected Options() {
		this.options = new ArrayList<Option>();
		this.options.add(new Option("enabled", null,
				"Confirms whether or not this option is enabled", Boolean.TRUE,
				Boolean.class, null));

	}

	protected static List<Integer> getIntListOption(String toBeParsed) {
		List<Integer> intList = new ArrayList<Integer>();
		for (String part : toBeParsed.split(LIST_SEPARATOR)) {
			intList.add(Integer.parseInt(part));
		}
		return intList;
	}

	protected static List<String> getStringListOption(String toBeParsed) {
		List<String> strList = new ArrayList<String>();
		if (!toBeParsed.isEmpty()) {
			for (String part : toBeParsed.split(LIST_SEPARATOR)) {
				strList.add(part);
			}
		}
		return strList;
	}

	protected static List<Float> getFloatListOption(String toBeParsed) {
		List<Float> floatList = new ArrayList<Float>();
		for (String part : toBeParsed.split(LIST_SEPARATOR)) {
			floatList.add(Float.parseFloat(part));
		}
		return floatList;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.ufpe.cin.imlm2.util.IOptions#parse(java.util.Map)
	 */
	@Override
	public void parse(Map<String, String> options) throws NoSuchOptionException {
		for (Entry<String, String> entry : options.entrySet()) {
			Option opt;
			if ((opt = this.getOption(entry.getKey())) != null) {
				Class<?> type = opt.getType();
				if (type.equals(String.class)) {
					opt.setValue(entry.getValue());
				} else if (type.equals(Integer.class)) {
					opt.setValue(Integer.parseInt(entry.getValue()));
				} else if (type.equals(Float.class)) {
					opt.setValue(Float.parseFloat(entry.getValue()));
				} else if (type.equals(Boolean.class)) {
					opt.setValue(Boolean.parseBoolean(entry.getValue()));
				} else if (type.equals(List.class)) {
					type = opt.getComponenType();
					if (type.equals(String.class)) {
						opt.setValue(getStringListOption(entry.getValue()));
					} else if (type.equals(Integer.class)) {
						opt.setValue(getIntListOption(entry.getValue()));
					} else if (type.equals(Float.class)) {
						opt.setValue(getFloatListOption(entry.getValue()));
					}
				}

			} else
				throw new NoSuchOptionException(entry.getKey(),
						"There is no option with name " + entry.getKey());

		}
	}

	protected Option getOption(String possibleName) {
		for (Option o : this.options) {
			if (o.getName().equals(possibleName)
					|| o.getAlias().equals(possibleName))
				return o;
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.ufpe.cin.imlm2.util.IOptions#getDeclaredOptions()
	 */
	@Override
	public List<String> getDeclaredOptions() {
		List<String> declaredOpts = new ArrayList<String>();
		for (Option o : this.options) {
			declaredOpts.add(o.getName());
		}
		return declaredOpts;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.ufpe.cin.imlm2.util.IOptions#getOptionValue(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public String getOptionValue(String optName) throws NoSuchOptionException {
		Option opt;
		if ((opt = this.getOption(optName)) != null) {
			if (!opt.getType().equals(List.class))
				return opt.getValue().toString();
			else {
				StringBuffer buffer = new StringBuffer();
				for (Object obj : (List<Object>) opt.getValue()) {
					buffer.append(obj.toString()).append(LIST_SEPARATOR);
				}
				if (buffer.length() > 0)
					buffer.deleteCharAt(buffer.length() - 1);
				return buffer.toString();
			}

		}

		throw new NoSuchOptionException(optName,
				"There is not option with name " + optName);
	}

	public boolean isEnabled() {
		return (Boolean) this.getOption("enabled").getValue();
	}

	@Override
	public String getAlias(String name) {
		Option opt;
		if ((opt = this.getOption(name)) != null)
			return opt.getAlias();
		return null;
	}

	@Override
	public String getHelp(String optName) {
		Option opt;
		if ((opt = this.getOption(optName)) != null) {
			return opt.getDescription();
		}
		return null;
	}

	@Override
	public boolean addOption(Option op) {
		if (!this.options.contains(op)) {
			this.options.add(op);
			return true;
		}
		return false;
	}

	@Override
	public List<Option> getOptions() {
		return new ArrayList<Option>(this.options);
	}

}
